package io.kiki.stack.netty.channelManager;


import io.kiki.stack.netty.exception.FutureTaskNotCompleted;
import io.kiki.stack.netty.exception.FutureTaskNotRunYetException;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.atomic.AtomicBoolean;

@Slf4j
@Setter
@Getter
public class RunStateRecordedFutureTask<V> extends FutureTask<V> {

    private final AtomicBoolean runned = new AtomicBoolean(false);

    public RunStateRecordedFutureTask(Callable<V> callable) {
        super(callable);
    }

    public static <T> T getFutureTaskResult(RunStateRecordedFutureTask<T> task) {
        T t = null;
        if (null != task) {
            try {
                t = task.getAfterRun();
            } catch (InterruptedException e) {
                log.error("Future task interrupted!", e);
            } catch (ExecutionException e) {
                log.error("Future task execute failed!", e);
            } catch (FutureTaskNotRunYetException e) {
                log.warn("Future task has not run yet!", e);
            } catch (FutureTaskNotCompleted e) {
                log.warn("Future task has not completed!", e);
            }
        }
        return t;
    }

    public static void launderThrowable(Throwable t) {
        if (t instanceof RuntimeException) {
            throw (RuntimeException) t;
        } else
            if (t instanceof Error) {
                throw (Error) t;
            } else {
                throw new IllegalStateException("Not unchecked!", t);
            }
    }

    @Override
    public void run() {
        this.runned.set(true);
        super.run();
    }

    public V getAfterRun() throws InterruptedException, ExecutionException, FutureTaskNotRunYetException, FutureTaskNotCompleted {
        if (!runned.get()) {
            throw new FutureTaskNotRunYetException();
        }

        if (!isDone()) {
            throw new FutureTaskNotCompleted();
        }

        return super.get();
    }
}